package com.yesep.learn.design.structural.adapter;

import com.yesep.learn.design.common.*;
import com.yesep.learn.design.common.util.*;

/**
 * 适配器模式（Adapter Pattern）是一种常用的设计模式，它主要用于解决接口不兼容的问题，使得原本由于接口不匹配而不能一起工作的类可以一起工作。
 * 这种模式可以视为两个不兼容接口之间的桥梁或中间层。以下是适配器模式的详细解析：
 * <p>
 * 一、定义与原理
 * 定义：适配器模式将一个类的接口转换成客户端所期待的另一种接口形式，从而使由于接口不兼容而不能一起工作的类可以一起工作。
 * 原理：通过创建一个新的类（即适配器类），该类既包含对原有类（适配者类）的引用，又实现了客户端所期待的接口（目标接口）。
 * 适配器类在内部将客户端的接口请求转换为对适配者类的相应调用。
 * 二、分类
 * 适配器模式主要分为两种类型：
 * <p>
 * 类适配器模式：
 * 通过多重继承对一个接口与另一个接口进行匹配。在Java等不支持多重继承的语言中，通常通过让适配器类继承适配者类并实现目标接口的方式来实现。
 * 优点：可以在适配器类中置换适配者类的方法，灵活性较强。
 * 缺点：对于不支持多重继承的语言，一次只能适配一个适配者类；适配者类不能为最终类（如Java中的final类）。
 * 对象适配器模式：
 * 通过组合的方式，将适配者类的实例嵌入到适配器类中，并通过持有适配者类的实例来实现目标接口。
 * 优点：解耦性好，可以将适配者类和目标接口的实现完全分离。
 * 缺点：与类适配器模式相比，在适配器中置换适配者类的方法较为困难。
 * 三、优点
 * 解耦：将目标类和适配者类解耦，使得它们之间不直接依赖。
 * 增加复用性：通过适配器，可以复用已有的类，而不必修改它们的代码。
 * 提高灵活性：适配器模式使得系统更加灵活，易于扩展和维护。
 * 四、应用场景
 * 当系统需要使用一些现有的类，而这些类的接口（如方法名）不符合系统的需要时。
 * 想使用一个已存在的类，但是该类不符合接口需求，或者需要创建一个可重用的类来适配没有提供合适接口的其它类。
 * 在数据库操作中，当需要连接不同的数据库（如MySQL和MongoDB），并希望使用统一的数据库操作接口时，适配器模式非常有用。
 * 五、示例
 * 以音频播放器为例，假设有一个老式的音频播放器类（OldAudioPlayer），其播放方法（playOldFormat）与客户端期望的新式播放接口（NewAudioPlayer）不兼容。
 * 可以通过创建一个适配器类（AudioPlayerAdapter）来解决这个问题，该类继承OldAudioPlayer并实现NewAudioPlayer接口，将playOldFormat方法的调用转换为play方法的调用。
 * <p>
 * 六、总结
 * 适配器模式是一种强大的设计模式，它通过引入一个适配器类来解决接口不兼容的问题，使得系统更加灵活、易于扩展和维护。在实际开发中，应根据具体场景选择合适的适配器类型来实现。
 */
public class Main {
    public static void main(String[] args) throws Exception {
        String mp3 = "hello.mp3";
        String mp4 = "hello.mp4";

        IMediaPlayer audioPlayer = DemoUtil.createAudioPlayer();
        IMediaPlayer videoPlayer = DemoUtil.createVideoPlayer();

        //类适配器模式
        MediaPlayerAPI mediaPlayerAPI = new MediaPlayerAPI();
        mediaPlayerAPI.play(audioPlayer, mp3);
        mediaPlayerAPI.pause(audioPlayer);
        mediaPlayerAPI.stop(audioPlayer);

        mediaPlayerAPI.play(videoPlayer, mp4);
        mediaPlayerAPI.pause(videoPlayer);
        mediaPlayerAPI.stop(videoPlayer);

        //对象适配器模式
        MediaAdapter audioAdapter = new MediaAdapter(audioPlayer);
        audioAdapter.play(mp3);
        audioAdapter.pause();
        audioAdapter.stop();

        MediaAdapter mediaAdapter = new MediaAdapter(videoPlayer);
        mediaAdapter.play(mp4);
        mediaAdapter.pause();
        mediaAdapter.stop();
    }
}
